import cherrypy
import os.path
from lxml import etree

class docbox:
    def __init__(self):
        self.parser = etree.XMLParser(remove_blank_text=True)
        self.xsltproc = etree.XSLT(etree.parse("docbox/xmldata.xsl", self.parser))
        
    def load(self, path, sheet):
        if path != "":
            self.path = path
        self.sheet = sheet
        
        try:
            self.doc = etree.parse(self.path, self.parser)
            self.res = self.xsltproc(self.doc, sheet=self.sheet)
        except TypeError, detail:
            return False
    
    def save(self):
        f = open(self.path, "w")
        f.write(etree.tostring(self.doc, pretty_print=True))
        f.close()
        
    def newunitbox(self, args):
        sheetel = self.doc.xpath("//sheetbox[@id='"+args["sheet"]+"']")[0]
        
        elid = genValidId(args['unitbox_new_id'])
        
        el = etree.Element("unitbox")
        el.set("id", elid)
        el.set("type", args['unitbox_new_type'])
        el.set("title", args['unitbox_new_title'])
        el.set("class", args['unitbox_new_class'])
        el.set("x", str(args['unitbox_new_x']) + 'px')
        el.set("y", str(args['unitbox_new_y']) + 'px')
        if args['unitbox_new_type'] == 'range':
            el.set("from", args['unitbox_new_rangefrom'])
            el.set("to", args['unitbox_new_rangeto'])
            el.set("step", args['unitbox_new_rangestep'])
        else:
            el.text = args['unitbox_new_value']
        
        sheetel.append(el)
        
        self.save()
        
        return True
    
    def deleteunitbox(self, args):
        el = self.doc.xpath("//unitbox[@id='" + args["unitbox_id"] + "']")[0]
        el.getparent().remove(el)
        
        self.save()
        
        return True
    
    def updateunitbox(self, args):
        el = self.doc.xpath("//unitbox[@id='" + args["unitbox_id"] + "']")[0]
        
        if "x" in args:
            el.set("x", args["x"])
        if "y" in args:
            el.set("y", args["y"])
        if "width" in args:
            el.set("width", args["width"])
        if "height" in args:
            el.set("height", args["height"])
        
        if "unitbox_type" in args:
            el.set("type", args["unitbox_type"])
            
            if "unitbox_rangefrom" in args and args["unitbox_type"] == 'range':
                el.set("from", args["unitbox_rangefrom"])
            if "unitbox_rangeto" in args and args["unitbox_type"] == 'range':
                el.set("to", args["unitbox_rangeto"])
            if "unitbox_rangestep" in args and args["unitbox_type"] == 'range':
                el.set("step", args["unitbox_rangestep"])
                
        if "unitbox_title" in args:
            el.set("title", args["unitbox_title"])
        if "unitbox_class" in args:
            el.set("class", args["unitbox_class"])
        
        if "unitbox_value" in args:
            el.text = args["unitbox_value"]
        
        self.save()
        
        return True
        
    def newsheetbox(self, args):
        elid = genValidId(args['sheetbox_new_title'])
        
        sheetel = etree.Element("sheetbox")
        sheetel.set("id", elid)
        
        titleel = etree.SubElement(sheetel, "title")
        titleel.set("id", elid + 'title')
        titleel.text = args['sheetbox_new_title']
        
        self.doc.getroot().append(sheetel)
        
        self.save()
        
        return elid
    
    def deletesheetbox(self):
        el = self.doc.xpath("//sheetbox[@id='" + args["sheet"] + "']")[0]
        el.getparent().remove(el)
        
        self.save()
        
        return True
    
    def __repr__(self):
        return str(self.res)

class boxfish:
    dbox = docbox()
    dbox_path = "docbox"
    
    def index(self):
        try:
            fp = open("gui/basic.bfg")
            tpl = fp.read()
            fp.close()
        except IOError:
            return "unable to open gui"
            
        return tpl
    index.exposed = True
    
    def getxmlcontent(self, **args):
        if "name" not in args:
            return "0"
        
        from pygments import highlight
        from pygments.lexers import XmlLexer
        from pygments.formatters import HtmlFormatter
        
        try:
            fp = open("docbox/" + args["name"] + "/" + args["name"] + ".xml")
            xml = fp.read()
            fp.close()
        except IOError:
            return "unable to open xml file"
        
        return "<style>" + HtmlFormatter().get_style_defs('.highlight') + "</style>" + highlight(xml, XmlLexer(), HtmlFormatter())
    getxmlcontent.exposed = True
    
    def getdialog(self, **args):
        if "name" not in args:
            return "0"
            
        try:
            fp = open("gui/" + args["name"])
            tpl = fp.read()
            fp.close()
        except IOError:
            return "unable to open gui"
        
        return tpl
    getdialog.exposed = True
    
    def parsedocbox(self, **args):
        
        if "sheet" not in args:
            args["sheet"] = "1"
        
        if "name" in args:
            docboxpath = os.path.join(self.dbox_path, args["name"] + "/" + args["name"] + ".xml")
        else:
            docboxpath = ""

        self.dbox.load(docboxpath, args["sheet"])
            
        return repr(self.dbox)
    parsedocbox.exposed = True
    
    def updateunitbox(self, **args):
        """ update a unitbox """
        
        #dbox = cherrypy.session.get("docbox")
        if self.dbox.updateunitbox(args):
            return "Unitbox successfully updated"
        else:
            return "Error! Unitbox not updated"
    updateunitbox.exposed = True
    
    def newunitbox(self, **args):
        """ create a new unitbox """
        
        if "sheet" not in args:
            return "Error! Sheet id not defined"

        if self.dbox.newunitbox(args):
            return "Unitbox successfully created"
        else:
            return "Error! Unitbox not created"
    newunitbox.exposed = True
    
    def deleteunitbox(self, **args):
        """ remove a unitbox """

        if self.dbox.deleteunitbox(args):
            return "Unitbox successfully removed"
        else:
            return "Error! Unitbox can not be removed"
    deleteunitbox.exposed = True
    
    def newsheetbox(self, **args):
        """ add a new sheetbox """
        
        if "sheet" not in args:
            return "Error! Sheet id not defined"
        
        if "sheetbox_new_title" not in args:
            return "Docbox not defined"
        
        return self.dbox.newsheetbox(args)
    newsheetbox.exposed = True
    
    def deletesheetbox(self, **args):
        """ remove a sheetbox from docbox """
        
        if self.dbox.deletesheetbox(args):
            return "Sheetbox successfully removed"
        else:
            return "Error! Sheetbox can not be removed"
    deletesheetbox.exposed = True
    
def genValidId(s):
    """ return a valid xml:id from a given string """
    
    elid = ""
    for c in s:
        if c not in 'qwertyuiopasdfghjklzxcvbnm1234567890':
            c = ""
        elid += c
    
    return elid
    
if __name__ == '__main__':
    confpath = os.path.join(os.path.dirname(__file__), 'conf/cherrypy.conf')
    if os.path.exists(confpath):
        conf = open(confpath)
        cherrypy.tree.mount(boxfish(), config=conf)
        cherrypy.engine.start()
    else:
        print "Warning! File conf/cherrypy.conf not found"
